﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LGPeWJNM.DataAccessLayer
{
    /// <summary>
    /// Dataset de instâncias
    /// </summary>
    public class InstanciaDataset : IDictionary<IdInstancia, Instancia>
    {
        /// <summary>
        /// Cria uma instância populada com os dados provinientes do http://www.branchandcut.org/
        /// <remarks>Somente as instâncias que possuem dados com distâncias eucledianas são carregados.</remarks>
        /// </summary>
        /// <param name="fileName">Caminho para o arquivo "Vrp-All.zip" obtido do site branch and cut</param>
        public InstanciaDataset(string fileName)
        {
            using (var zs = Ionic.Zip.ZipFile.Read(fileName))
            {
                Keys = (from e in zs.EntryFileNames
                        where e.EndsWith("vrp")
                        select new IdInstancia() { Classe = e.Split('/')[0], Instancia = e.Split('/')[1].Split('.')[0] }).ToList();
                Values = zs.Entries.Where(s => s.FileName.EndsWith("vrp")).Select(s =>
                {
                    using (var ms = new System.IO.MemoryStream())
                    using (var sr = new System.IO.StreamReader(ms))
                    {
                        s.Extract(ms);
                        ms.Position = 0;
                        return new Instancia(sr);
                    }
                }).ToList();
            }
        }

        public InstanciaDataset(IdInstancia idInstancia, Instancia instancia)
        {
            this.Add(idInstancia, instancia);
        }

        /// <summary>
        /// Método não implementado
        /// </summary>
        /// <exception cref="NotImplementedException">Método não implementado</exception>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void Add(IdInstancia key, Instancia value)
        {
            this.Keys = new List<IdInstancia>();
            this.Values = new List<Instancia>();
            this.Keys.Add(key);
            this.Values.Add(value);
            //throw new NotImplementedException();
        }

        /// <summary>
        /// Verifica se há uma identificação neste Dataset
        /// </summary>
        /// <param name="key">Identificação a ser verificada</param>
        /// <returns>Retorna true caso seja encontrada a instância, caso contrário retorna false.</returns>
        public bool ContainsKey(IdInstancia key)
        {
            return Keys.Contains(key);
        }

        /// <summary>
        /// Coleção de identificações das instâncias neste Dataset
        /// </summary>
        public ICollection<IdInstancia> Keys { get; private set; }

        /// <summary>
        /// Método não implementado
        /// </summary>
        /// <exception cref="NotImplementedException">Método não implementado</exception>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool Remove(IdInstancia key)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Tenta recuperar um valor do Dataset
        /// </summary>
        /// <param name="key">Identificação da instância a ser recuperada</param>
        /// <param name="value">A instância será recuperada neste parâmetro de saída</param>
        /// <returns>Retorna true caso seja encontrada a instância, caso contrário retorna false.</returns>
        public bool TryGetValue(IdInstancia key, out Instancia value)
        {
            if (Keys.Contains(key))
            {
                value = Values.ElementAt(Keys.ToList().IndexOf(key));
                return true;
            }
            else
            {
                value = null;
                return false;
            }
        }

        /// <summary>
        /// Coleção dos valores contidos neste Dataset
        /// </summary>
        public ICollection<Instancia> Values { get; private set; }

        /// <summary>
        /// Gets the value associated with the specified key.
        /// </summary>
        /// <param name="key">The key of the value to get or set.</param>
        /// <exception cref="NotImplementedException">Não é possível definir um novo elemento em um Dataset somente leitura</exception>
        /// <exception cref="System.Collections.Generic.KeyNotFoundException">Se for solicitado um elemento que não há na coleção será retornado uma exceção</exception>
        /// <returns>The value associated with the specified key. If the specified key is not
        /// found, a get operation throws a System.Collections.Generic.KeyNotFoundException</returns>
        public Instancia this[IdInstancia key]
        {
            get
            {
                return Values.ElementAt(Keys.ToList().IndexOf(key));
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        /// <summary>
        /// Método não implementado
        /// </summary>
        /// <exception cref="NotImplementedException">Método não implementado</exception>
        /// <param name="item"></param>
        public void Add(KeyValuePair<IdInstancia, Instancia> item)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Método não implementado
        /// </summary>
        /// <exception cref="NotImplementedException">Método não implementado</exception>
        public void Clear()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Verifica se existe um par IdInstancia, Instancia neste Dataset
        /// </summary>
        /// <param name="item">Item a ser verificado se está contido neste Dataset</param>
        /// <returns>Retorna true caso seja encontrato equivalente dentro da coleção</returns>
        public bool Contains(KeyValuePair<IdInstancia, Instancia> item)
        {
            var q = from k in Keys
                    join v in Values
                    on Keys.ToList().IndexOf(k) equals Values.ToList().IndexOf(v)
                    select new KeyValuePair<IdInstancia, Instancia>(k, v);
            return q.Contains(item);
        }

        /// <summary>
        /// Método não implementado
        /// </summary>
        /// <exception cref="NotImplementedException">Método não implementado</exception>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        public void CopyTo(KeyValuePair<IdInstancia, Instancia>[] array, int arrayIndex)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Retorna o número de elementos deste Dataset
        /// </summary>
        public int Count
        {
            get { return Keys.Count; }
        }

        /// <summary>
        /// Indica que esta coleção é somente leitura
        /// </summary>
        public bool IsReadOnly
        {
            get { return true; }
        }

        /// <summary>
        /// Método não implementado
        /// </summary>
        /// <exception cref="NotImplementedException">Método não implementado</exception>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Remove(KeyValuePair<IdInstancia, Instancia> item)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Returns an enumerator that iterates through the System.Collections.Generic.Dictionary
        /// </summary>
        /// <returns>An Enumerator structure for the System.Collections.Generic.Dictionary.</returns>
        public IEnumerator<KeyValuePair<IdInstancia, Instancia>> GetEnumerator()
        {
            var q = from k in Keys
                    join v in Values
                    on Keys.ToList().IndexOf(k) equals Values.ToList().IndexOf(v)
                    select new KeyValuePair<IdInstancia, Instancia>(k, v);
            return q.GetEnumerator();
        }

        /// <summary>
        /// Returns an enumerator that iterates through the System.Collections.Generic.Dictionary
        /// </summary>
        /// <returns>An Enumerator structure for the System.Collections.Generic.Dictionary.</returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return Keys.GetEnumerator();
            throw new NotImplementedException();
        }
    }
}